#include <asm/domain_page.h>
#include <asm/flushtlb.h>
#include <asm/msr.h>
-#include <xeno/multiboot.h>
#include <xeno/blkdev.h>
#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_USER|_PAGE_ACCESSED)
#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_USER|_PAGE_ACCESSED|_PAGE_DIRTY)
-extern int nr_mods;
-extern module_t *mod;
-extern unsigned char *cmdline;
-
rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED;
/*
for ( alloc_pfns = 0; alloc_pfns < req_pages; alloc_pfns++ )
{
pf = list_entry(temp, struct pfn_info, list);
- pf->flags |= p->domain;
+ pf->flags = p->domain;
pf->type_count = pf->tot_count = 0;
temp = temp->next;
list_del(&pf->list);
/* setup_guestos is used for building dom0 solely. other domains are built in
* userspace dom0 and final setup is being done by final_setup_guestos.
*/
-int setup_guestos(struct task_struct *p, dom0_newdomain_t *params)
+int setup_guestos(struct task_struct *p, dom0_newdomain_t *params,
+ char *data_start, unsigned long data_len, char *cmdline)
{
-
struct list_head *list_ent;
char *src, *dst;
int i, dom = p->domain;
/* Sanity! */
if ( p->domain != 0 ) BUG();
- if ( strncmp(__va(mod[0].mod_start), "XenoGues", 8) )
+ if ( strncmp(data_start, "XenoGues", 8) )
{
printk("DOM%d: Invalid guest OS image\n", dom);
return -1;
}
- virt_load_address = *(unsigned long *)__va(mod[0].mod_start + 8);
+ virt_load_address = *(unsigned long *)(data_start + 8);
if ( (virt_load_address & (PAGE_SIZE-1)) )
{
printk("DOM%d: Guest OS load address not page-aligned (%08lx)\n",
alloc_address <<= PAGE_SHIFT;
alloc_index = p->tot_pages;
- if ( (mod[nr_mods-1].mod_end-mod[0].mod_start) >
- (params->memory_kb << 9) )
+ if ( data_len > (params->memory_kb << 9) )
{
printk("DOM%d: Guest OS image is too large\n"
" (%luMB is greater than %uMB limit for a\n"
" %uMB address space)\n",
- dom, (mod[nr_mods-1].mod_end-mod[0].mod_start)>>20,
+ dom, data_len>>20,
(params->memory_kb)>>11,
(params->memory_kb)>>10);
free_all_dom_mem(p);
__write_cr3_counted(pagetable_val(p->mm.pagetable));
/* Copy the guest OS image. */
- src = (char *)__va(mod[0].mod_start + 12);
+ src = (char *)(data_start + 12);
dst = (char *)virt_load_address;
- while ( src < (char *)__va(mod[nr_mods-1].mod_end) ) *dst++ = *src++;
+ while ( src < (data_start+data_len) ) *dst++ = *src++;
/* Set up start info area. */
memset(virt_startinfo_address, 0, sizeof(*virt_startinfo_address));
/* Add block io interface */
virt_startinfo_address->blk_ring = virt_to_phys(p->blk_ring_base);
- /* We tell OS about any modules we were given. */
- if ( nr_mods > 1 )
- {
- virt_startinfo_address->mod_start =
- (mod[1].mod_start-mod[0].mod_start-12) + virt_load_address;
- virt_startinfo_address->mod_len =
- mod[nr_mods-1].mod_end - mod[1].mod_start;
- }
-
dst = virt_startinfo_address->cmd_line;
- if ( mod[0].string )
+ if ( cmdline != NULL )
{
- char *modline = (char *)__va(mod[0].string);
for ( i = 0; i < 255; i++ )
{
- if ( modline[i] == '\0' ) break;
- *dst++ = modline[i];
+ if ( cmdline[i] == '\0' ) break;
+ *dst++ = cmdline[i];
}
}
*dst = '\0';
#include <stdarg.h>
#include <xeno/lib.h>
#include <xeno/errno.h>
-#include <xeno/multiboot.h>
#include <xeno/spinlock.h>
+#include <xeno/multiboot.h>
#include <xeno/sched.h>
#include <xeno/mm.h>
#include <xeno/delay.h>
unsigned long type; /* type of memory segment */
};
-/* Used by domain.c:setup_guestos */
-int nr_mods;
-module_t *mod;
-
void init_vga(void);
void init_serial(void);
void start_of_day(void);
dom0_newdomain_t dom0_params;
unsigned long max_page;
unsigned char *cmdline;
+ module_t *mod;
int i;
/*
}
#endif
- nr_mods = mbi->mods_count;
- mod = (module_t *)__va(mbi->mods_addr);
+ mod = (module_t *)__va(mbi->mods_addr);
/* Parse the command line. */
cmdline = (unsigned char *)(mbi->cmdline ? __va(mbi->cmdline) : NULL);
printk("Initialised all memory on a %luMB machine\n",
max_page >> (20-PAGE_SHIFT));
- init_page_allocator(mod[nr_mods-1].mod_end, MAX_MONITOR_ADDRESS);
+ init_page_allocator(mod[0].mod_end, MAX_MONITOR_ADDRESS);
/* These things will get done by do_newdomain() for all other tasks. */
current->shared_info = (void *)get_free_page(GFP_KERNEL);
new_dom = do_newdomain(0, 0);
if ( new_dom == NULL ) panic("Error creating domain 0\n");
- if ( setup_guestos(new_dom, &dom0_params) != 0 )
- {
- panic("Could not set up DOM0 guest OS\n");
- }
- update_dom_time(new_dom->shared_info);
+ if ( setup_guestos(new_dom,
+ &dom0_params,
+ __va(mod[0].mod_start),
+ mod[0].mod_end - mod[0].mod_start,
+ __va(mod[0].string))
+ != 0 ) panic("Could not set up DOM0 guest OS\n");
+
+ release_bytes_to_allocator(__pa(&_end), mod[0].mod_end);
+
+ update_dom_time(new_dom->shared_info);
wake_up(new_dom);
cpu_idle();
return -1;
}
+ page->flags &= ~PG_type_mask;
page->flags |= type;
}
static int dec_page_refcnt(unsigned long page_nr, unsigned int type)
{
struct pfn_info *page;
- int ret;
if ( page_nr >= max_page )
{
return -1;
}
ASSERT(page_type_count(page) != 0);
- if ( (ret = put_page_type(page)) == 0 ) page->flags &= ~PG_type_mask;
put_page_tot(page);
- return ret;
+ return put_page_type(page);
}
page_type_count(page));
return(-1);
}
+ page->flags &= ~PG_type_mask;
page->flags |= PGT_writeable_page;
}
+ page->flags &= ~PG_noflush;
get_page_type(page);
}
((page_type_count(page) != 0) &&
((page->flags & PG_type_mask) == PGT_writeable_page)));
if ( writeable && (put_page_type(page) == 0) )
- {
tlb_flush[smp_processor_id()] = 1;
- page->flags &= ~PG_type_mask;
- }
put_page_tot(page);
}
#define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
-/* Initialise allocator, placing addresses [@min,@max] in free pool. */
+/*
+ * Initialise allocator, placing addresses [@min,@max] in free pool.
+ * @min and @max are PHYSICAL addresses.
+ */
void __init init_page_allocator(unsigned long min, unsigned long max)
{
int i;
}
-/* Allocate 2^@order contiguous pages. */
+/* Release a PHYSICAL address range to the allocator. */
+void release_bytes_to_allocator(unsigned long min, unsigned long max)
+{
+ min = round_pgup (min) + PAGE_OFFSET;
+ max = round_pgdown(max) + PAGE_OFFSET;
+
+ while ( min < max )
+ {
+ __free_pages(min, 0);
+ min += PAGE_SIZE;
+ }
+}
+
+
+/* Allocate 2^@order contiguous pages. Returns a VIRTUAL address. */
unsigned long __get_free_pages(int mask, int order)
{
int i, attempts = 0;
}
-/* Free 2^@order pages at location @p. */
+/* Free 2^@order pages at VIRTUAL address @p. */
void __free_pages(unsigned long p, int order)
{
unsigned long size = 1 << (order + PAGE_SHIFT);
/* If reading into the frame, the frame must be writeable. */
if ( writeable_buffer &&
- ((page->flags & PG_type_mask) != PGT_writeable_page) )
+ ((page->flags & PG_type_mask) != PGT_writeable_page) &&
+ (page->type_count != 0) )
{
DPRINTK("non-writeable page passed for block read\n");
goto out;
pfn++ )
{
page = frame_table + pfn;
- if ( writeable_buffer ) get_page_type(page);
+ if ( writeable_buffer )
+ {
+ if ( page->type_count == 0 )
+ {
+ page->flags &= ~PG_type_mask;
+ /* NB. This ref alone won't cause a TLB flush. */
+ page->flags |= PGT_writeable_page | PG_noflush;
+ }
+ get_page_type(page);
+ }
get_page_tot(page);
}
}
pfn++ )
{
page = frame_table + pfn;
- if ( writeable_buffer && (put_page_type(page) == 0) )
- page->flags &= ~PG_type_mask;
+ if ( writeable_buffer &&
+ (put_page_type(page) == 0) &&
+ !(page->flags & PG_noflush) )
+ {
+ __flush_tlb();
+ }
+ page->flags &= ~PG_noflush;
put_page_tot(page);
}
spin_unlock_irqrestore(&p->page_lock, flags);
#define capable(_c) 0
#ifndef __ASSEMBLY__
+extern unsigned long _end; /* standard ELF symbol */
extern void __out_of_line_bug(int line) __attribute__((noreturn));
#define out_of_line_bug() __out_of_line_bug(__LINE__)
#endif
*/
void init_page_allocator(unsigned long min, unsigned long max);
+void release_bytes_to_allocator(unsigned long min, unsigned long max);
unsigned long __get_free_pages(int mask, int order);
void __free_pages(unsigned long p, int order);
#define get_free_page(_m) (__get_free_pages((_m),0))
* with struct pfn_info and frame_table respectively. Boris Dragovic
*/
-/*
- * This is still fatter than I'd like. Do we need the count?
- * Do we need the flags? The list at least seems req'd by slab.c.
- */
typedef struct pfn_info {
struct list_head list; /* ->mapping has some page lists. */
unsigned long flags; /* atomic flags. */
#define PGT_writeable_page (7<<24) /* has writable mappings of this page? */
#define PGT_net_rx_buf (8<<24) /* this page has been pirated by the net code. */
+/*
+ * This bit is sometimes set by Xen when it holds a writeable reference to a
+ * page that shouldn't cause a TLB flush when it is dropped. For example, a
+ * disk write to a page with initial type_count == 0, which returns to 0 after
+ * the I/O. In this case, we'd normally flush the TLB because a writeable page
+ * has just lost its mutually-exclusive type. But this isn't necessary here
+ * because the writeable reference never made it into user-accessible TLB
+ * (didn't make it into TLB at all, in fact).
+ *
+ * This bit is obviously nuked in a few places, for safety.
+ */
+#define PG_noflush (1<<28)
+
#define PageSlab(page) test_bit(PG_slab, &(page)->flags)
#define PageSetSlab(page) set_bit(PG_slab, &(page)->flags)
#define PageClearSlab(page) clear_bit(PG_slab, &(page)->flags)
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#ifndef __MULTIBOOT_H__
+#define __MULTIBOOT_H__
+
#ifndef __ELF__
#error "Build on a 32-bit ELF system"
#endif
unsigned long length_high;
unsigned long type;
} memory_map_t;
+
+#endif /* __MULTIBOOT_H__ */
extern struct task_struct first_task_struct;
extern struct task_struct *do_newdomain(unsigned int dom_id, unsigned int cpu);
-extern int setup_guestos(struct task_struct *p, dom0_newdomain_t *params);
+extern int setup_guestos(
+ struct task_struct *p, dom0_newdomain_t *params,
+ char *data_start, unsigned long data_len, char *cmdline);
extern int final_setup_guestos(struct task_struct *p, dom_meminfo_t *);
struct task_struct *find_domain_by_id(unsigned int dom);
h_pfn->tot_count = h_pfn->type_count = 1;
g_pfn->tot_count = g_pfn->type_count = 0;
- h_pfn->flags = g_pfn->flags & (~PG_type_mask);
+ h_pfn->flags = g_pfn->flags & ~PG_type_mask;
if (*g_pte & _PAGE_RW) h_pfn->flags |= PGT_writeable_page;
g_pfn->flags = 0;